Room是一個本地資料庫與SQLiteDataBase相同,他一樣也提供了CRUD的一些註解做使用,在應用程式做清除資料的時候資料也會隨之而消失,那麼就開始今日的主題,首先需要在gradle中加入一些依賴:
plugins{
//...
id 'kotlin-kapt'
id 'kotlin-android-extensions'
}
android{
//...
}
dependcies{
//room
implementation"androidx.room:room-runtime:2.4.3"
annotationProcessor"androidx.room:room-compiler:2.4.3"
androidTestImplementation "androidx.room:room-testing:2.4.3"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1"
kapt "androidx.lifecycle:lifecycle-compiler:2.3.0-alpha07"
kapt "androidx.room:room-compiler:2.3.0-alpha02"
}
那麼首先先附上今日UI:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Account"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.59" />
<EditText
android:id="@+id/et_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Password"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.704" />
<Button
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新增"
android:textSize="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.779"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.853" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.35" />
<TextView
android:id="@+id/txv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.468" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改"
android:textSize="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.242"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.853" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/itemId"
android:layout_width="70dp"
android:layout_height="match_parent"
android:textSize="28dp"
android:text="" />
<TextView
android:id="@+id/itemText"
android:layout_width="300dp"
android:layout_height="match_parent"
android:textSize="28dp"
android:text="" />
<ImageButton
android:id="@+id/btn_delete"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#00FF0000"
app:srcCompat="@android:drawable/ic_menu_delete" />
</LinearLayout>
class DataAdapter(val activity: MainActivity , dataList:MutableList<DataModel>) : RecyclerView.Adapter<DataAdapter.ViewHolder>() {
var arrayList:MutableList<DataModel> = dataList
var onItemClick:OnItemClickListener?=null
var onItemDelete:OnItemDeleteListener?=null
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemId = itemView.findViewById<TextView>(R.id.itemId)
val itemText = itemView.findViewById<TextView>(R.id.itemText)
val btn_delete = itemView.findViewById<ImageButton>(R.id.btn_delete)
}
//刪除
fun deleteData(position: Int){
Thread {
Log.d("DeleteTag","pos:"+position)
DataBase.getInstance(activity)!!.userDao().delete(arrayList[position])
}.start()
notifyItemRemoved(position)
arrayList.remove(arrayList[position])
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_data,null))
}
override fun getItemCount(): Int {
return arrayList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.btn_delete.setOnClickListener {
deleteData(position)
onItemDelete?.onItemDelete(position)
}
holder.itemId.setText(""+(position+1))
holder.itemText.setText(""+arrayList.get(position).account)
//view點擊事件
holder.itemView.setOnClickListener{
Log.d("click",""+onItemClick)
onItemClick?.onItemClick(arrayList[position],position)
}
}
interface OnItemClickListener {
fun onItemClick(myData: DataModel,position:Int)
}
interface OnItemDeleteListener{
fun onItemDelete(position:Int)
}
}
Room主要可由三大部分組成:
@Entity(tableName="user")
data class DataModel(
@PrimaryKey(autoGenerate = true)
var _id: Int,
@ColumnInfo(name = "Account")
var account :String,
@ColumnInfo(name = "Password")
var password:String
)
@Dao
interface Dao {
//新增資料(當發生衝突則覆蓋)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUser(data: DataModel)
//取得user資料表的所有資料
@Query("SELECT * FROM user")
fun getAll(): MutableList<DataModel>
//更新資料
@Update
fun updateUser(data: DataModel)
//刪除資料
@Delete
fun delete(data: DataModel)
}
@Database(entities = [DataModel::class], version = 1)
abstract class DataBase : RoomDatabase() {
abstract fun userDao(): Dao
companion object {
private var instance: DataBase? = null
fun getInstance(context: Context): DataBase? {
if (instance == null) {
instance = create(context) //新增資料庫
}
return instance
}
private fun create(context: Context): DataBase{
return Room.databaseBuilder(context, DataBase::class.java, "Application.db").build()
}
}
}
需要注意的是,當執行資料庫的方法處理時,需要開另一個執行緒或協程去執行,不然會報錯。
那麼接著最後來設計需要的activity:
class MainActivity : AppCompatActivity(){
//資料List
lateinit var users: MutableList<DataModel>
//RecyclerView調配器
var dataAdapter:DataAdapter? = null
//執行crud、query語法
var userDao : Dao ?= null
//RecyclerView的position
var cyclePos :Int = -1
//資料的id
var pos :Int = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Thread{
//資料庫建立
val db = DataBase.getInstance(applicationContext)
if (db != null) {
userDao = db.userDao()
//更新清單顯示
setRecyclerView()
}
}.start()
//新增按鈕
btn_send.setOnClickListener { view->
if (!et_account.text.toString().equals("")&&!et_password.text.toString().equals("")){
Log.d("TAGGGG","SEND!"+userDao)
txv_show.setText("新增1筆資料")
Thread {
//新增資料
userDao?.insertUser(DataModel(0,et_account.text.toString(),et_password.text.toString()))
//更新清單顯示
setRecyclerView()
//輸入框清空
runOnUiThread {
et_account.setText("")
et_password.setText("")
}
}.start()
//將點擊項目的position設-1
pos=-1
}
}
//更新按鈕
btn_update.setOnClickListener { view->
if (!et_account.text.toString().equals("")&&!et_password.text.toString().equals("")) {
Log.d("TAGGGG","UPDATE!"+userDao)
txv_show.setText("已更新第"+(cyclePos+1)+"筆")
Thread {
//更新資料
userDao?.updateUser(DataModel(pos,et_account.text.toString(),et_password.text.toString()))
//更新清單顯示
setRecyclerView()
runOnUiThread {
//輸入框清空
et_account.setText("")
et_password.setText("")
}
}.start()
}
}
}
//更新清單顯示、項目點擊、刪除按紐處理
fun setRecyclerView(){
users = userDao!!.getAll()
runOnUiThread {
dataAdapter = DataAdapter(MainActivity(),users)
recyclerview.setLayoutManager(LinearLayoutManager(this)) //使用LinearLayout布局
recyclerview.adapter=dataAdapter
//項目點擊事件
dataAdapter?.onItemClick = object :DataAdapter.OnItemClickListener{
override fun onItemClick(myData: DataModel,position:Int) {
//資料的id
pos=myData._id
//list的position
cyclePos=position
txv_show.setText("選取第"+(cyclePos+1)+"筆")
et_account.setText(""+myData.account)
et_password.setText(""+myData.password)
}
}
//刪除按紐事件
dataAdapter?.onItemDelete = object :DataAdapter.OnItemDeleteListener {
override fun onItemDelete(position: Int) {
txv_show.setText("已刪除第"+(position+1)+"筆")
}
}
}
}
}